package procilege.lang;

import java.util.Collection;
import java.util.HashSet;

import merisis.util.BitUtil;

import org.apache.solr.util.OpenBitSet;

import procilege.impl.NameImpl;

public class PrivilegeFormTerm {

	public OpenBitSet fucntions = new OpenBitSet();

	public OpenBitSet entities = new OpenBitSet();

	public Collection<PredicateExpr> restrictions = new HashSet<PredicateExpr>();

	public OpenBitSet bearers = new OpenBitSet();

	public PrivilegeFormTerm() {

	}

	public Name getFunctionName() {

		long id = fucntions.nextSetBit(0);
		NameImpl name = new NameImpl(id);
		if (fucntions.nextSetBit(id + 1) >= 0) {
			StringBuilder sb = new StringBuilder();
			sb.append("No complete reduction: ");
			BitUtil.format(sb, fucntions, ",");
			throw new IllegalStateException(sb.toString()); 
		}

		return name;
	}

	public OpenBitSet getFucntions() {
		return fucntions;
	}

	public OpenBitSet getEntities() {
		return entities;
	}

	public Collection<PredicateExpr> getRestrictions() {
		return restrictions;
	}

	public void mergeNormalTerm(PrivilegeFormTerm pnt) {

		this.bearers.or(pnt.bearers);
		this.entities.or(pnt.entities);
		this.fucntions.or(pnt.fucntions);
		this.restrictions.addAll(pnt.restrictions);
	}

	public void mergePrivExpr(PrivExprElement pv) {

		if (pv instanceof Name) {
			this.fucntions.set(((NameImpl) pv).getNameSN());
		} else if (pv instanceof ExprSubstitute) {
			mergePrivExpr((ExprSubstitute) pv);
		} else {
			throw new IllegalStateException("obj: " + pv);
		}
	}

	public void mergeEntityName(EntityExprElement ent) {

		if (!(ent instanceof Name))
			throw new IllegalStateException("name required: " + ent);

		this.entities.set(((NameImpl) ent).getNameSN());
	}

	public void mergePredicateExpr(BoolExprElement expr) {

		if (!(expr instanceof PredicateExpr))
			throw new IllegalStateException("predicate required: " + expr);

		restrictions.add((PredicateExpr) expr);
	}

	public boolean isEmptyFunction() {

		return this.fucntions.cardinality() == 1;
	}

	public void addOrigin(Name name) {
		bearers.set(((NameImpl) name).nameId);
	}
}